package org.focuser.buildbot;

import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.waveprotocol.wave.model.id.WaveId;
import org.waveprotocol.wave.model.id.WaveletId;

import com.google.wave.api.AbstractRobot;
import com.google.wave.api.Blip;
import com.google.wave.api.BlipContentRefs;
import com.google.wave.api.Wavelet;
import com.google.wave.api.event.WaveletSelfAddedEvent;

@SuppressWarnings("serial")
public class Buildbot extends AbstractRobot {
	
	private static final String RPC_SERVER_URL = "http://gmodules.com/api/rpc";
	private Map<String, Set<Tuple<WaveId, WaveletId>>> mWaveIdMap = new HashMap<String, Set<Tuple<WaveId, WaveletId>>>();
	private Map<String, String> mInsersionPointMap = new HashMap<String, String>();

	public Buildbot() {
		Properties props = new Properties();
//		try {
			/*
			 * the file is in WEB-INF/classes
			 */
//			InputStream inputStream = this.getClass().getClassLoader()  
//			.getResourceAsStream("/credentials.properties");
//			props.load(inputStream);
//			String CONSUMER_KEY = props.getProperty("ConsumerKey");
//			String CONSUMER_SECRET = props.getProperty("ConsumerSecret");
			String CONSUMER_KEY = "962850858068";
			String CONSUMER_SECRET="BpU80uHBRuaSi8uqLspvVFOH";
			setupOAuth(CONSUMER_KEY, CONSUMER_SECRET, RPC_SERVER_URL);
			setAllowUnsignedRequests(true);
//		} catch (Exception e) {
//			// TODO Auto-generated catch block
//			log("setupOAuth failed.", e);
//		}
	}
	
	@Override
	protected String getRobotName() {
		return "Build-Bot";
	}
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
		super.doGet(req, resp);
		publishToWave(req, resp);
	}
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
		super.doPost(req, resp);
		publishToWave(req, resp);
	}

	private void publishToWave(HttpServletRequest req, HttpServletResponse resp) {
		String projectId = req.getParameter("projectId");
		if (projectId==null || projectId.trim().length()==0)
			return;
		String content = req.getParameter("content");
		Set<Tuple<WaveId, WaveletId>> idSet = mWaveIdMap.get(projectId);
		String insertionPoint = mInsersionPointMap.get(projectId);
		int all = 0, ok = 0;
		if (idSet!=null) {
			all = idSet.size();
			for (Tuple<WaveId, WaveletId> ids:idSet) {
				boolean success = publishToWave(ids.getFirst(), ids.getSecond(), insertionPoint , content);
				if (success) ok++;
			}
		}
		int fail = all - ok;
		try {
			resp.getWriter().format("all=%d, ok=%d, fail=%d", all, ok, fail);
		} catch (IOException e) {
			log("unable to write to response.", e);
		}
	}
	
	@Override
	public void init() throws ServletException {
	}
	
	@Override
	public void destroy() {
		super.destroy();
	}
	
	@Override
	public void onWaveletSelfAdded(WaveletSelfAddedEvent event) {
		Wavelet wavelet = event.getWavelet();
		Blip rootBlip = wavelet.getRootBlip();
		String content = rootBlip.getContent();
//		Pattern pattern = Pattern.compile("(\\n(\\w+)\\s+builds\\r|\\n|(\\r\\n)|(\\n\\r)).*");
		Pattern pattern = Pattern.compile("(\\s*(\\w+)\\s+builds\\s+)");
		Matcher m = pattern.matcher(content);
//		log(String.format("I'm added to wave:%s"+wavelet.getWaveId().getId()));
		if (m.find()) {
			String projectId = m.group(2);
			Set<Tuple<WaveId, WaveletId>> idSet = mWaveIdMap.get(projectId);
			if (idSet==null) {
				idSet = new HashSet<Tuple<WaveId, WaveletId>>();
				mWaveIdMap.put(projectId, idSet);
			}
			idSet.add(new Tuple<WaveId, WaveletId>(wavelet.getWaveId(), wavelet.getWaveletId()));
			mInsersionPointMap.put(projectId, m.group(1));
			wavelet.reply(String.format(
					"\nI'm alive!  I will automatically post svn logs and binary download links after a build is done.\n" +
					"projectId=%s\n" +
					"content=%s", projectId,content));
		} else
			wavelet.reply(String.format(
					"\nI'm alive!  But I couldn't determine the projectId from this wave, so I won't do anything.\n" +
					"content=%s", content));
	}

	private boolean publishToWave(WaveId waveId, WaveletId waveletId, String insertionPoint, String content) {
		if (waveId!=null&&waveletId!=null) {
			try {
				Wavelet wavelet = fetchWavelet(waveId, waveletId, RPC_SERVER_URL);
				Blip blip = wavelet.getRootBlip();
				String target = insertionPoint;
				BlipContentRefs refs = blip.first(target);
				refs.insertAfter(content);
				submit(wavelet, RPC_SERVER_URL);
				return true;
			} catch (IOException e) {
				log("Failed to publish to wave:"+waveId.getId(), e);
				throw new RuntimeException(e);
			}
		}
		return false;
	}
	
	@Override
	public void log(String message, Throwable t) {
		RuntimeException ex = new RuntimeException(message, t);
		throw ex;
	}
}
